/*
 * Copyright (C) 2024 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the 'License');
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an 'AS IS' BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef IMAGE_KNIFE_C_DOWNLOAD_INTERCEPTOR_OH_H
#define IMAGE_KNIFE_C_DOWNLOAD_INTERCEPTOR_OH_H

#include "imageknife_task_internal.h"
#include "interceptor.h"
#include "imageknife_request.h"
#include "imageknife_data_napi.h"
#include <future>

namespace ImageKnifeC {

extern std::multimap<std::string, std::string> &GetGlobaHttpHeaders();

class DownloadInterceptorOH : public DownloadInterceptor {
public:
    DownloadInterceptorOH()
    {
        name = "Default DownloadInterceptor";
    }

    bool Resolve(std::shared_ptr<ImageKnifeTask> task) override
    {
        std::string url;
        if (task->GetImageSource()->GetString(url)) {
            return LoadImageFromUrl(url, task);
        }

        return false;
    }

    void Cancel(std::shared_ptr<ImageKnifeTask> task) override
    {
        auto taskInternal = std::static_pointer_cast<ImageKnifeTaskInternal>(task);
        if (taskInternal->rcpRequest != nullptr && taskInternal->rcpSession != nullptr) {
            uint32_t errorCode = HMS_Rcp_CancelRequest(taskInternal->rcpSession, taskInternal->rcpRequest);
            uint32_t errCodeSession = HMS_Rcp_CancelSession(taskInternal->rcpSession);
            if (!errorCode && !errCodeSession) {
                task->cancelInfo = "Cancel Download Success";
            } else {
                task->EchoError("Cancel Download Failed, error code: " + std::to_string(errorCode) + " , : " +
                                std::to_string(errCodeSession));
            }
        }
    }

private:
    // Rcp 异步回调数据
    struct CallbackData {
        uint32_t errCode = 0;
        int httpCode = RCP_OK;
        std::promise<std::string> promise;
        Rcp_Response* response = nullptr;
    };

    Rcp_Headers *CreateRcpHeaders(std::multimap<std::string, std::string> &head)
    {
        if (head.size() == 0) {
            return nullptr;
        }
        Rcp_Headers *rcpHeaders = HMS_Rcp_CreateHeaders();
        for (auto it = head.begin(); it != head.end(); it++) {
            HMS_Rcp_SetHeaderValue(rcpHeaders, it->first.c_str(), it->second.c_str());
        }
        return rcpHeaders;
    }

    bool LoadImageFromUrl(std::string url, std::shared_ptr<ImageKnifeTask> task)
    {
        auto taskInternal = std::static_pointer_cast<ImageKnifeTaskInternal>(task);
        // 网络请求下载阶段
//         task->request->imageKnifeData.errorInfo.phase = ImageKnifeDataNapi::phaseToStringMap[LoadPhase::NETWORK_FETCH];
//         task->request->imageKnifeData.timeInfo.netRequestStartTime = ImageKnifeDataNapi::GetTimestamp();
        taskInternal->rcpRequest = HMS_Rcp_CreateRequest(url.c_str());
        if (taskInternal->rcpRequest == nullptr) {
            task->EchoError("Create Rcp Request Failed");
            return false;
        }
        ConfigHttpRequest(taskInternal);

        uint32_t errCode = 0;
        // session不是线程安全的，不能简单的进行全局复用，后续考虑管理一个session池
        taskInternal->rcpSession = HMS_Rcp_CreateSession(NULL, &errCode);
        // 获取网络状态码
//         task->request->imageKnifeData.httpCode = errCode;
        if (errCode) {
//             task->request->imageKnifeData.timeInfo.netRequestEndTime = ImageKnifeDataNapi::GetTimestamp();
//             task->request->imageKnifeData.errorInfo.code = LoadPixelMapCode::HTTPS_LOAD_FAILED;
            task->EchoError("create Session error: " + std::to_string(errCode));
            DestroyConfiguration(taskInternal);
            HMS_Rcp_DestroyRequest(taskInternal->rcpRequest);
            return false;
        }

        CallbackData data;
        Rcp_ResponseCallbackObject callback = {ResponseCallback, &data};
        errCode = HMS_Rcp_Fetch(taskInternal->rcpSession, taskInternal->rcpRequest, &callback);
        if (errCode) {
            data.promise.set_value("HMS_Rcp_Fetch error: " + std::to_string(errCode));
        }
        // 等待异步下载过程结束
        std::string info = data.promise.get_future().get();
        // 释放资源
        DestroyConfiguration(taskInternal);
        HMS_Rcp_DestroyRequest(taskInternal->rcpRequest);
        HMS_Rcp_CloseSession(&taskInternal->rcpSession);
//         task->request->imageKnifeData.timeInfo.netRequestEndTime = ImageKnifeDataNapi::GetTimestamp();

        if (data.response != nullptr) {
            taskInternal->rcpResponse = data.response;
            // 提供空的删除器避免错误析构
            taskInternal->product.imageBuffer = std::shared_ptr<uint8_t>((uint8_t *)data.response->body.buffer,
                                                                         [](void* ) {});
            taskInternal->product.imageLength = data.response->body.length;
            return true;
        } else if (!info.empty()){ // 成功取消下载info可能为空
            task->EchoError(info);
        }

        return false;
    }

    void DestroyConfiguration(std::shared_ptr<ImageKnifeTaskInternal> task)
    {
        if (task->rcpRequest->headers != nullptr) {
            HMS_Rcp_DestroyHeaders(task->rcpRequest->headers);
        }

        if (task->rcpRequest->configuration != nullptr) {
            delete task->rcpRequest->configuration;
        }
    }

    void ConfigHttpRequest(std::shared_ptr<ImageKnifeTaskInternal> task)
    {
        task->rcpRequest->headers = CreateRcpHeaders(task->GetImageKnifeRequest()->
            GetImageKnifeOption()->httpHeaders);
        if (task->rcpRequest->headers == nullptr) {
            task->rcpRequest->headers = CreateRcpHeaders(GetGlobaHttpHeaders());
        }

        // 设置为Get请求
        task->rcpRequest->method = RCP_METHOD_GET;

        // 设置下载进度监听回调
        if (task->GetImageKnifeRequest()->GetImageKnifeOption()->progressListener != nullptr &&
            task->GetImageRequestType() == ImageRequestType::MAIN_SRC) {
            Rcp_Configuration *config = new Rcp_Configuration;
            memset(config, 0, sizeof(Rcp_Configuration));
            config->tracingConfiguration.httpEventsHandler.onDownloadProgress = {.callback = OnProgressCallback,
                .usrObject = &(task->GetImageKnifeRequest()->GetImageKnifeOption()->progressListener)};
            task->rcpRequest->configuration = config;
        }
    }

    static void OnProgressCallback(void* userObject, uint64_t totalSize, uint64_t transferredSize)
    {
        if (totalSize > 0) {
            std::function<void(double)>* userFunc = static_cast<std::function<void(double)>*>(userObject);
            (*userFunc)(static_cast<double>(transferredSize) / totalSize);
        }
    }

    static void ResponseCallback(void *usrCtx, Rcp_Response *response, uint32_t errCode)
    {
        const int httpDownloadCanceled = 1007900992;
        CallbackData *data = static_cast<CallbackData*>(usrCtx);
        data->errCode = errCode;
        std::string errorInfo;
        if (errCode) {
            if (errCode != httpDownloadCanceled) {
                errorInfo = "HttpFetch HMS_Rcp_Fetch error:" + std::to_string(errCode);
            }
        }

        if (response != NULL) {
            data->httpCode = response->statusCode;
            if (response->statusCode != RCP_OK) {
                errorInfo = "HttpFetch response error, statusCode: " + std::to_string(response->statusCode);
                response->destroyResponse(response);
            } else {
                data->response = response;
            }
        }

        data->promise.set_value(errorInfo);
    }
};

};

#endif // IMAGE_KNIFE_C_DOWNLOAD_INTERCEPTOR_OH_H
